local extension = Package("joy")

Fk:loadTranslationTable{
  ["joy"] = "热门武将",

  -- TODO: move them
  ["m_ex"] = "手杀界",
  ["ol_ex"] = "OL界",
  ["ex"] = "界限突破",
}

local liuyan = General(extension, "liuyan", "qun", 3)
local tushe = fk.CreateTriggerSkill{
  name = "tushe",
  anim_type = "drawcard",
  events = {fk.TargetSpecified},
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and
      data.card.type ~= Card.TypeEquip and
      data.firstTarget and
      #table.filter(player:getCardIds(Player.Hand), function(cid)
        return Fk:getCardById(cid).type == Card.TypeBasic
      end) == 0 and
      #AimGroup:getAllTargets(data.tos) > 0
  end,
  on_use = function(self, event, target, player, data)
    player:drawCards(#AimGroup:getAllTargets(data.tos), self.name)
  end,
}
liuyan:addSkill(tushe)
local limubuff = fk.CreateTargetModSkill{
  name = "#limubuff",
  residue_func = function(self, player, skill)
    return #player:getCardIds(Player.Judge) > 0 and 999 or 0
  end,
  distance_limit_func = function(self, player, skill)
    return #player:getCardIds(Player.Judge) > 0 and 999 or 0
  end,
}
local limu = fk.CreateActiveSkill{
  name = "limu",
  anim_type = "control",
  target_num = 0,
  card_num = 1,
  can_use = function(self, player) return not player:hasDelayedTrick("indulgence") end,
  target_filter = function() return false end,
  card_filter = function(self, to_select, selected)
    return #selected == 0 and Fk:getCardById(to_select).suit == Card.Diamond
  end,
  on_use = function(self, room, use)
    local player = room:getPlayerById(use.from)
    local cards = use.cards
    local marks = player:getMark("_rende_cards")
    local le = Fk:cloneCard("indulgence")
    le:addSubcards(cards)
    room:useCard{
      from = use.from,
      tos = { { use.from } },
      card = le,
    }
    if player:isWounded() then
      room:recover{
        who = player,
        num = 1,
        skillName = self.name
      }
    end
  end,
}
limu:addRelatedSkill(limubuff)
liuyan:addSkill(limu)

Fk:loadTranslationTable{
  ["liuyan"] = "刘焉",
  ["tushe"] = "图射",
  [":tushe"] = "当你使用非装备牌指定目标后，若你没有基本牌，则你可以摸X张牌（X为此牌指定的目标数）。",
  ["limu"] = "立牧",
  [":limu"] = "出牌阶段，你可以将一张方块牌当【乐不思蜀】对自己使用，然后回复1点体力；你的判定区有牌时，你使用牌没有次数和距离限制。",
}

local liuzan = General(extension, "liuzan", "wu", 4)
local fenyin = fk.CreateTriggerSkill{
  name = "fenyin",
  anim_type = "drawcard",
  events = {fk.CardUsing},
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and
      player.phase < Player.NotActive and self.can_fenyin
  end,
  on_use = function(self, event, target, player, data)
    player:drawCards(1, self.name)
  end,

  refresh_events = {fk.CardUsing, fk.EventPhaseStart},
  can_refresh = function(self, event, target, player, data)
    if not (target == player and player:hasSkill(self.name)) then return end
    if event == fk.EventPhaseStart then
      return player.phase == Player.NotActive
    else
      return player.phase < Player.NotActive -- FIXME: this is a bug of FK 0.0.2!!
    end
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.EventPhaseStart then
      room:setPlayerMark(player, self.name, 0)
      room:setPlayerMark(player, "@" .. self.name, 0)
    else
      self.can_fenyin = data.card.color ~= player:getMark(self.name) and player:getMark(self.name) ~= 0
      room:setPlayerMark(player, self.name, data.card.color)
      room:setPlayerMark(player, "@" .. self.name, data.card:getColorString())
    end
  end,
}
liuzan:addSkill(fenyin)
Fk:loadTranslationTable{
  ["liuzan"] = "留赞",
  ["fenyin"] = "奋音",
  [":fenyin"] = "你的回合内，当你使用和上一张牌颜色不同的牌时，你可以摸一张牌。",
  ["@fenyin"] = "奋音",
}

local wangji = General(extension, "wangji", "wei", 3)
Fk:loadTranslationTable{
  ["wangji"] = "王基",
}

local qizhi = fk.CreateTriggerSkill{
  name = "qizhi",
  anim_type = "control",
  events = { fk.TargetSpecified },
  can_trigger = function(self, event, target, player, data)
    return 
      target == player and
      player:hasSkill(self.name) and
      player.phase < Player.NotActive and 
      data.firstTarget and
      table.contains({ Card.TypeBasic, Card.TypeTrick }, data.card.type)
  end,
  on_cost = function(self, event, target, player, data)
    local room = player.room
    local alivePlayers = room:getAlivePlayers()
    local availableTargets = {}
    for _, p in ipairs(alivePlayers) do
      if not p:isNude() and not table.contains(AimGroup:getAllTargets(data.tos), p.id) then
        table.insert(availableTargets, p.id)
      end
    end

    if #availableTargets == 0 then
      return false
    end

    local result = room:askForChoosePlayers(player, availableTargets, 1, 1, "#qizhi-ask", self.name)
    if #result > 0 then
      self.cost_data = result
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local skillTarget = room:getPlayerById(self.cost_data[1])
    local card = room:askForCardChosen(player, skillTarget, "he", self.name)
    room:throwCard(card, self.name, skillTarget, skillTarget)
    skillTarget:drawCards(1, self.name)
    room:addPlayerMark(player, "@" .. self.name)
  end,

  refresh_events = {fk.EventPhaseStart},
  can_refresh = function(self, event, target, player, data)
    if not (target == player and player:hasSkill(self.name)) then return end
    return player.phase == Player.NotActive
  end,
  on_refresh = function(self, event, target, player, data)
    player.room:setPlayerMark(player, "@" .. self.name, 0)
  end,
}
Fk:loadTranslationTable{
  ["qizhi"] = "奇制",
  [":qizhi"] = "当你使用基本牌或锦囊牌指定第一个目标后，你可以弃置一名不为目标的角色的一张牌，然后令其摸一张牌。",
  ["@qizhi"] = "奇制",
  ["#qizhi-ask"] = "奇制：你可以弃置一名非目标角色的一张牌，然后令其摸一张牌",
}
wangji:addSkill(qizhi)

local jinqu = fk.CreateTriggerSkill{
  name = "jinqu",
  anim_type = "drawcard",
  events = { fk.EventPhaseStart },
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and player.phase == Player.Finish
  end,
  on_use = function(self, event, target, player, data)
    player:drawCards(2, self.name)
    local diff = #player:getCardIds(Player.Hand) - player:getMark("@" .. qizhi.name)
    if diff > 0 then
      player.room:askForDiscard(player, diff, diff, false, self.name)
    end
  end,
}
Fk:loadTranslationTable{
  ["jinqu"] = "进趋",
  [":jinqu"] = "结束阶段开始时，你可以摸两张牌，然后将手牌弃置至X张（X为你于本回合内发动过“奇制”的次数。",
}
wangji:addSkill(jinqu)

local quyi = General(extension, "quyi", "qun", 4)
Fk:loadTranslationTable{
  ["quyi"] = "麴义",
}

local fuji = fk.CreateTriggerSkill{
  name = "fuji",
  anim_type = "offensive",
  events = { fk.CardUsing },
  frequency = Skill.Compulsory,
  can_trigger = function(self, event, target, player, data)
    return
      target == player and
      player:hasSkill(self.name) and
      (data.card.trueName == "slash" or (data.card.type == Card.TypeTrick and data.card.sub_type ~= Card.SubtypeDelayedTrick)) and
      #table.filter(player.room:getOtherPlayers(player), function(curPlayer)
        return curPlayer:distanceTo(player) == 1
      end) > 0
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local availableTargets = table.filter(room:getOtherPlayers(player), function(curPlayer)
      return curPlayer:distanceTo(player) == 1
    end)

    if #availableTargets > 0 then
      data.disresponsiveList = data.disresponsiveList or {}
      for _, target in ipairs(availableTargets) do
        table.insertIfNeed(data.disresponsiveList, target.id)
      end
    end
  end,
}
Fk:loadTranslationTable{
  ["fuji"] = "伏骑",
  [":fuji"] = "锁定技，当你使用【杀】或普通锦囊牌时，你令所有至你距离为1的角色不能响应此牌。",
}
quyi:addSkill(fuji)

local jiaozi = fk.CreateTriggerSkill{
  name = "jiaozi",
  anim_type = "offensive",
  events = { fk.DamageCaused, fk.DamageInflicted },
  frequency = Skill.Compulsory,
  can_trigger = function(self, event, target, player, data)
    return
      target == player and
      player:hasSkill(self.name) and
      table.every(player.room:getOtherPlayers(player), function(curPlayer) 
        return #player:getCardIds(Player.Hand) > #curPlayer:getCardIds(Player.Hand)
      end)
  end,
  on_use = function(self, event, target, player, data)
    data.damage = data.damage + 1
  end,
}
Fk:loadTranslationTable{
  ["jiaozi"] = "骄恣",
  [":jiaozi"] = "锁定技，当你造成或受到伤害时，若你的手牌为全场唯一最多，则此伤害+1。",
}
quyi:addSkill(jiaozi)

local m_ex__xusheng = General(extension, "m_ex__xusheng", "wu", 4)
local m_ex__pojun_clean = fk.CreateTriggerSkill{
  name = "#m_ex__pojun_clean",
  mute = true,
  events = {fk.EventPhaseStart},
  can_trigger = function(self, event, target, player, data)
    return target.phase >= Player.NotActive and
      #player:getPile("m_ex__pojun") > 0
  end,
  on_cost = function() return true end,
  on_use = function(self, event, target, player, data)
    local dummy = Fk:cloneCard("zixing")
    dummy:addSubcards(player:getPile("m_ex__pojun"))
    local room = player.room
    room:obtainCard(player.id, dummy, false)
  end,
}
local m_ex__pojun = fk.CreateTriggerSkill{
  name = "m_ex__pojun",
  anim_type = "offensive",
  events = {fk.TargetSpecified},
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and
      data.card.trueName == "slash" and not player.room:getPlayerById(data.to):isNude()
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local to = room:getPlayerById(data.to)
    local cards = room:askForCardsChosen(player, to, 0, to.hp, "he", self.name)
    to:addToPile(self.name, cards, false, self.name)
  end,
  
  refresh_events = {fk.DamageCaused},
  can_refresh = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and
      data.card and data.card.trueName == "slash" and
      #player:getCardIds(Player.Hand) >= #data.to:getCardIds(Player.Hand) and
      #player:getCardIds(Player.Equip) >= #data.to:getCardIds(Player.Equip) and
      not data.chain
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    room:broadcastSkillInvoke(self.name)
    room:notifySkillInvoked(player, self.name)
    data.damage = data.damage + 1
  end,
}
m_ex__pojun:addRelatedSkill(m_ex__pojun_clean)
m_ex__xusheng:addSkill(m_ex__pojun)
Fk:loadTranslationTable{
  ["m_ex__xusheng"] = "界徐盛",
  ["m_ex__pojun"] = "破军",
  ["#m_ex__pojun_clean"] = "破军",
  [":m_ex__pojun"] = "当你使用【杀】指定一个目标后，你可以将其至多X张牌扣置于该角色的武将牌旁（X为其体力值）；若如此做，当前回合结束后，该角色获得这些牌。你使用【杀】对手牌数与装备数均不大于你的角色造成伤害时，此伤害+1。",
}

local xizhicai = General(extension, "xizhicai", "wei", 3)
xizhicai:addSkill("tiandu")
local xianfu = fk.CreateTriggerSkill{
  name = "xianfu",
  events = {fk.GameStart, fk.Damaged, fk.HpRecover},
  frequency = Skill.Compulsory,
  can_trigger = function(self, event, target, player, data)
    if event == fk.GameStart then return player:hasSkill(self.name) end
    return target:getMark(self.name) == player.id and player:hasSkill(self.name) and not target.dead
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    if event == fk.GameStart then
      local to = room:askForChoosePlayers(player, table.map(room:getOtherPlayers(player), function(p)
        return p.id
      end), 1, 1, "#xianfu-choose", self.name)[1]
      to = room:getPlayerById(to)
      room:setPlayerMark(to, self.name, player.id)
    elseif event == fk.Damaged then
      local mark_name = "@" .. self.name
      if player:getMark(mark_name) == 0 then
        room:setPlayerMark(player, mark_name, target.general)
      end
      room:damage{
        to = player,
        damage = data.damage,
        skillName = self.name,
      }
    elseif event == fk.HpRecover then
      local mark_name = "@" .. self.name
      if player:getMark(mark_name) == 0 then
        room:setPlayerMark(player, mark_name, target.general)
      end
      room:recover{
        who = player,
        num = data.num,
        skillName = self.name,
      }
    end
  end,
}
xizhicai:addSkill(xianfu)
local chouce = fk.CreateTriggerSkill{
  name = "chouce",
  anim_type = "masochism",
  events = {fk.Damaged},
  on_trigger = function(self, event, target, player, data)
    self.cancel_cost = false
    for i = 1, data.damage do
      if self.cancel_cost then break end
      self:doCost(event, target, player, data)
    end
  end,
  on_cost = function(self, event, target, player, data)
    local room = player.room
    if room:askForSkillInvoke(player, self.name, data) then
      return true
    end
    self.cancel_cost = true
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local judge = {
      who = player,
      reason = self.name,
    }
    room:judge(judge)
    if judge.card.color == Card.Red then
      local to = room:askForChoosePlayers(player, table.map(room:getAlivePlayers(), function(p)
        return p.id
      end), 1, 1, "#chouce-draw", self.name)[1]
      to = room:getPlayerById(to)
      to:drawCards(1 + (to:getMark("xianfu") == player.id and 1 or 0), self.name)
    elseif judge.card.color == Card.Black then
      local targets = table.filter(room:getAlivePlayers(), function(p)
        return not p:isAllNude()
      end)
      local to = room:askForChoosePlayers(player, table.map(targets, function(p)
        return p.id
      end), 1, 1, "#chouce-discard", self.name)[1]
      to = room:getPlayerById(to)
      local card = room:askForCardChosen(player, to, "hej", self.name)
      room:throwCard(card, self.name, to)
    end
  end,
}
xizhicai:addSkill(chouce)
Fk:loadTranslationTable{
  ["xizhicai"] = "戏志才",
  ["xianfu"] = "先辅",
  ["@xianfu"] = "先辅",
  [":xianfu"] = "锁定技，游戏开始时，你选择一名其他角色，当其受到伤害后，你受到等量的伤害；当其回复体力后，你回复等量的体力。",
  ["chouce"] = "筹策",
  [":chouce"] = "当你受到1点伤害后，你可以进行判定，若结果为：黑色，你弃置一名角色区域里的一张牌；红色，你令一名角色摸一张牌（先辅的角色摸两张）。",
  ["#xianfu-choose"] = "先辅: 请选择要先辅的角色",
  ["#chouce-draw"] = "筹策: 请选择一名角色令其摸牌",
  ["#chouce-discard"] = "筹策: 请选择一名角色，弃置其区域内的牌",
}

-- Because packages are loaded before gamelogic.lua loaded
-- so we can not directly create subclass of gamelogic in the top of lua
local m_1v2_getLogic = function()
  local m_1v2_logic = GameLogic:subclass("m_1v2_logic")

  function m_1v2_logic:initialize(room)
    GameLogic.initialize(self, room)
    self.role_table = {nil, nil, {"lord", "rebel", "rebel"}}
  end

  function m_1v2_logic:chooseGenerals()
    local room = self.room
  local generalNum = room.settings.generalNum
    local function setPlayerGeneral(player, general)
      if Fk.generals[general] == nil then return end
      player.general = general
      player.gender = Fk.generals[general].gender
      self.room:broadcastProperty(player, "general")
      self.room:broadcastProperty(player, "gender")
    end

    local lord = room:getLord()
    room.current = lord
    local nonlord = room.players
    local generals = Fk:getGeneralsRandomly(#nonlord * generalNum)
    table.shuffle(generals)
    for _, p in ipairs(nonlord) do
      local arg = {}
      for i = 1, generalNum do
        table.insert(arg, table.remove(generals, 1).name)
      end
      p.request_data = json.encode(arg)
      p.default_reply = arg[1]
    end

    room:doBroadcastRequest("AskForGeneral", nonlord)
    for _, p in ipairs(nonlord) do
      if p.general == "" and p.reply_ready then
        local general = json.decode(p.client_reply)[1]
        setPlayerGeneral(p, general)
      else
        setPlayerGeneral(p, p.default_reply)
      end
      p.default_reply = ""
    end
  end

  return m_1v2_logic
end

local m_feiyang = fk.CreateTriggerSkill{
  name = "m_feiyang",
  anim_type = "control",
  events = {fk.EventPhaseStart},
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and
      player.phase == Player.Judge and
      #player:getCardIds(Player.Hand) >= 2 and
      #player:getCardIds(Player.Judge) > 0
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    room:askForDiscard(player, 2, 2, false, self.name, false)
    local card = room:askForCardChosen(player, player, "j", self.name)
    room:throwCard(card, self.name, player, player)
  end
}
Fk:addSkill(m_feiyang)
local m_bahubuff = fk.CreateTargetModSkill{
  name = "#m_bahubuff",
  residue_func = function(self, player, skill, scope)
    if player:hasSkill(self.name) and skill.trueName == "slash_skill"
      and scope == Player.HistoryPhase then
      return 1
    end
  end,
}
local m_bahu = fk.CreateTriggerSkill{
  name = "m_bahu",
  anim_type = "drawcard",
  frequency = Skill.Compulsory,
  events = {fk.EventPhaseStart},
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and
      player.phase == Player.Start
  end,
  on_use = function(self, event, target, player, data)
    player:drawCards(1)
  end,
}
m_bahu:addRelatedSkill(m_bahubuff)
Fk:addSkill(m_bahu)
local m_1v2_rule = fk.CreateTriggerSkill{
  name = "#m_1v2_rule",
  priority = 0.001,
  refresh_events = {fk.GameStart, fk.BuryVictim},
  can_refresh = function(self, event, target, player, data)
    if event == fk.GameStart then return player.role == "lord" end
    return target == player
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.GameStart then
      room:handleAddLoseSkills(player, "m_feiyang|m_bahu", nil, false)
      player.maxHp = player.maxHp + 1
      player.hp = player.hp + 1
      room:broadcastProperty(player, "maxHp")
      room:broadcastProperty(player, "hp")
      room:setTag("SkipNormalDeathProcess", true)
    else
      for _, p in ipairs(room.alive_players) do
        if p.role == "rebel" then
          local choices = {"m_1v2_draw2", "Cancel"}
          if p:isWounded() then
            table.insert(choices, 2, "m_1v2_heal")
          end
          local choice = room:askForChoice(p, choices, self.name)
          if choice == "m_1v2_draw2" then p:drawCards(2)
          else room:recover{ who = p, num = 1, skillName = self.name } end
        end
      end
    end
  end,
}
Fk:addSkill(m_1v2_rule)
local m_1v2_mode = fk.CreateGameMode{
  name = "m_1v2_mode",
  minPlayer = 3,
  maxPlayer = 3,
  rule = m_1v2_rule,
  logic = m_1v2_getLogic,
}
extension:addGameMode(m_1v2_mode)
Fk:loadTranslationTable{
  ["m_1v2_mode"] = "欢乐斗地主",
  ["m_feiyang"] = "飞扬",
  ["m_bahu"] = "跋扈",
  ["#m_1v2_rule"] = "挑选遗产",
  ["m_1v2_draw2"] = "摸两张牌",
  ["m_1v2_heal"] = "回复1点体力",

  [":m_1v2_mode"] = [[
# 欢乐斗地主模式简介

___

总体规则类似身份局。游戏由三人进行，一人扮演地主（主公），其他两人扮演农民（反贼）。

地主增加一点体力上限和体力，且拥有以下额外技能：

- **飞扬**：判定阶段开始时，你可以弃置两张手牌并弃置自己判定区内的一张牌。

- **跋扈**：锁定技，准备阶段，你摸一张牌；出牌阶段，你可以多使用一张杀。

当农民被击杀后，另一名农民可以选择：摸两张牌，或者回复一点体力。

*击杀农民的人没有摸三张牌的奖励。*

胜利规则与身份局一致。
  ]],
}

local dujin = fk.CreateTriggerSkill{
  name = "dujin",
  anim_type = "drawcard",
  events = {fk.DrawNCards},
  on_use = function(self, event, target, player, data)
    data.n = data.n + 1 + #player:getCardIds(Player.Equip) // 2
  end,
}
local lingcao = General(extension, "lingcao", "wu", 4)
lingcao:addSkill(dujin)
Fk:loadTranslationTable{
  ["lingcao"] = "凌操",
  ["dujin"] = "独进",
  [":dujin"] = "摸牌阶段，你可以多摸X+1张牌，" ..
    "X为你装备区内牌数的一半（向下取整）",
}

local ol_ex__weiyan = General(extension, "ol_ex__weiyan", "shu", 4)
local ol_ex__kuanggu = fk.CreateTriggerSkill{
  name = "ol_ex__kuanggu",
  anim_type = "drawcard",
  events = {fk.Damage},
  can_trigger = function(self, event, target, player, data)
    return player:hasSkill(self.name) and target == player
      and player:distanceTo(data.to) <= 1
  end,
  on_trigger = function(self, event, target, player, data)
    self.cancel_cost = false
    for i = 1, data.damage do
      self:doCost(event, target, player, data)
      if self.cost_data == "Cancel" then break end
    end
  end,
  on_cost = function(self, event, target, player, data)
    local room = player.room
    local choices = {"draw1card", "Cancel"}
    if player:isWounded() then table.insert(choices, 2, "heal1hp") end
    self.cost_data = room:askForChoice(player, choices, self.name)
    return self.cost_data ~= "Cancel"
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    if self.cost_data == "heal1hp" then
      room:recover({
        who = player,
        num = 1,
        recoverBy = player,
        skillName = self.name
      })
    elseif self.cost_data == "draw1card" then
      player:drawCards(1, self.name)
    end
  end,
}
local ol_ex__qimouBuff = fk.CreateTargetModSkill{
  name = "#ol_ex__qimouBuff",
  residue_func = function(self, player, skill, scope)
    if skill.trueName == "slash_skill" and scope == Player.HistoryPhase then
      return player:getMark("@ol_ex__qimou") or 0
    end
  end,
}
local ol_ex__qimouDistance = fk.CreateDistanceSkill{
  name = "#ol_ex__qimouDistance",
  global = true, -- FIXME
  correct_func = function(self, from, to)
    return -from:getMark("@ol_ex__qimou")
  end,
}
Fk:addSkill(ol_ex__qimouDistance) --FIXME
local ol_ex__qimouCleaner = fk.CreateTriggerSkill{
  name = "#ol_ex__qimouCleaner",
  refresh_events = {fk.EventPhaseStart},
  can_refresh = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name)
      and player.phase == Player.NotActive
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    room:setPlayerMark(player, "@ol_ex__qimou", 0)
  end,
}
local ol_ex__qimou = fk.CreateActiveSkill{
  name = "ol_ex__qimou",
  anim_type = "offensive",
  frequency = Skill.Limited,
  can_use = function(self, player)
    -- TODO: fk未完成的功能之一，考虑后面自动判断限定或者觉醒
    return player:usedSkillTimes(self.name, Player.HistoryGame) == 0
  end,
  target_num = 0,
  card_num = 0,
  on_use = function(self, room, effect)
    local player = room:getPlayerById(effect.from)
    -- TODO: 这里应该给fk加新功能，视为/主动技使用之前应该有个额外的交互
    local choices = {}
    for i = 1, player.hp do
      table.insert(choices, tostring(i))
    end
    local tolose = tonumber(room:askForChoice(player, choices, self.name))
    room:loseHp(player, tolose, self.name)
    player:drawCards(tolose)
    room:setPlayerMark(player, "@ol_ex__qimou", tolose)
  end,
}
ol_ex__qimou:addRelatedSkill(ol_ex__qimouBuff)
--ol_ex__qimou:addRelatedSkill(ol_ex__qimouDistance) --FIXME
ol_ex__qimou:addRelatedSkill(ol_ex__qimouCleaner)
ol_ex__weiyan:addSkill(ol_ex__kuanggu)
ol_ex__weiyan:addSkill(ol_ex__qimou)
Fk:loadTranslationTable{
  ["ol_ex__weiyan"] = "界魏延",
  ["ol_ex__kuanggu"] = "狂骨",
  [":ol_ex__kuanggu"] = "你对距离1以内的角色造成1点伤害后，可以选择:" ..
    "1. 摸一张牌； 2. 回复一点体力。",
  ["draw1card"] = "摸一张牌",
  ["heal1hp"] = "回复一点体力",
  ["ol_ex__qimou"] = "奇谋",
  ["@ol_ex__qimou"] = "奇谋",
  [":ol_ex__qimou"] = "限定技。出牌阶段，你可以失去X点体力，本回合内" ..
    "与其他角色计算距离-X且可以多使用X张杀。",
}

local qinzheng = fk.CreateTriggerSkill{
  name = "qinzheng",
  anim_type = "drawcard",
  frequency = Skill.Compulsory,
  events = {fk.CardUsing, fk.CardResponding},
  can_trigger = function(self, event, target, player, data)
    return
      target == player and
      player:hasSkill(self.name) and
      not table.every({ 3, 5, 8 }, function(num)
        return player:getMark("@" .. self.name) % num ~= 0
      end)
  end,
  on_use = function(self, event, player, target, data)
    local randCard = function(cardName)
      local cardNum = #player.room.draw_pile
      local randNum = math.random(1, cardNum)
      
      for i = randNum, cardNum do
        local card = Fk:getCardById(player.room.draw_pile[i])
        
        if table.contains(cardName, card.name) then
          return card
        end
      end
      
      for i = 1, randNum do
        local card = Fk:getCardById(player.room.draw_pile[i])
        
        if table.contains(cardName, card.name) then
          return card
        end
      end
      
      return nil
    end

    local loopList = table.filter({ 3, 5, 8 }, function(num)
      return player:getMark("@" .. self.name) % num == 0
    end)

    local toObtain = {}
    for _, count in ipairs(loopList) do
      local cardList = {"slash", "jink"}
      if count == 5 then
        cardList = {"peach", "analeptic"}
      elseif count == 8 then
        cardList = {"ex_nihilo", "duel"}
      end

      local randomCard = randCard(cardList)
      if randomCard then
        table.insert(toObtain, randomCard.id)
      end
    end

    if #toObtain > 0 then
      player.room:moveCards({
        ids = toObtain,
        to = player.id,
        toArea = Player.Hand,
        moveReason = fk.ReasonPrey,
        proposer = player.id,
        skillName = self.name,
      })
    end
  end,

  refresh_events = {fk.PreCardUse, fk.PreCardRespond},
  can_refresh = function(self, event, target, player, data)
    return player:hasSkill(self.name) and target == player
  end,
  on_refresh = function(self, event, target, player, data)
    player.room:addPlayerMark(player, "@" .. self.name, 1)
  end,
}

local luotong = General:new(extension, "luotong", "wu", 4)
luotong:addSkill(qinzheng)

Fk:loadTranslationTable{
  ["luotong"] = "骆统",
  ["qinzheng"] = "勤政",
  [":qinzheng"] = "锁定技，你每使用或打出：三张牌时，你随机获得一张【杀】或【闪】；五张牌时，你随机获得一张【桃】或【酒】；八张牌时，你随机获得一张【无中生有】或【决斗】。",
  ["@qinzheng"] = "勤政",
}

local lijue = General(extension, "lijue", "qun", 4, 6)
Fk:loadTranslationTable{
  ["lijue"] = "李傕",
}

local langxi = fk.CreateTriggerSkill{
  name = "langxi",
  anim_type = "offensive",
  events = { fk.EventPhaseStart },
  can_trigger = function(self, event, target, player, data)
    return
      target == player and
      player:hasSkill(self.name) and
      player.phase == Player.Start and
      not table.every(player.room:getOtherPlayers(player), function(p)
        return p.hp > player.hp
      end)
  end,
  on_cost = function(self, event, target, player, data)
    local room = player.room
    local target = room:askForChoosePlayers(
      player,
      table.map(
        table.filter(room:getOtherPlayers(player), function(p)
          return p.hp <= player.hp
        end),
        function(p)
          return p.id
        end
      ),
      1,
      1,
      "#langxi-ask",
      self.name
    )

    if #target > 0 then
      self.cost_data = target[1]
      return true
    end

    return false
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    room:damage({
      from = player,
      to = room:getPlayerById(self.cost_data),
      damage = math.random(0, 2),
      damageType = fk.NormalDamage,
      skillName = self.name,
    })
  end,
}
Fk:loadTranslationTable{
  ["langxi"] = "狼袭",
  [":langxi"] = "准备阶段开始时，你可以对一名体力值不大于你的其他角色随机造成0~2点伤害。",
  ["#langxi-ask"] = "狼袭：请选择一名体力值不大于你的其他角色，对其随机造成0~2点伤害",
}
lijue:addSkill(langxi)

local yisuan = fk.CreateTriggerSkill{
  name = "yisuan",
  anim_type = "drawcard",
  events = { fk.CardUseFinished },
  can_trigger = function(self, event, target, player, data)
    return
      target == player and
      player:hasSkill(self.name) and
      player.phase == Player.Play and
      player:usedSkillTimes(self.name) < 1 and
      data.card.type == Card.TypeTrick and
      data.card.sub_type ~= Card.SubtypeDelayedTrick and
      player.room:getCardArea(data.card) == Card.Processing
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    room:changeMaxHp(player, -1)
    room:obtainCard(player.id, data.card, true, fk.ReasonPrey)
  end,
}
Fk:loadTranslationTable{
  ["yisuan"] = "亦算",
  [":yisuan"] = "每阶段限一次，当你于出牌阶段内使用普通锦囊牌结算结束后，你可以减1点体力上限，然后获得此牌。",
}
lijue:addSkill(yisuan)

local ex__huanggai = General(extension, "ex__huanggai", "wu", 4)
local ex__kurou = fk.CreateActiveSkill{
  name = "ex__kurou",
  anim_type = "negative",
  can_use = function(self, player)
    return player:usedSkillTimes(self.name) == 0
  end,
  target_num = 0,
  card_num = 1,
  on_use = function(self, room, effect)
    local from = room:getPlayerById(effect.from)
    room:throwCard(effect.cards, self.name, from)
    room:loseHp(from, 1, self.name)
  end
}
ex__huanggai:addSkill(ex__kurou)
local zhaxiangBuff = fk.CreateTargetModSkill{
  name = "#zhaxiangBuff",
  residue_func = function(self, player, skill, scope)
    if skill.trueName == "slash_skill" and scope == Player.HistoryPhase then
      return player.phase ~= Player.NotActive and player:usedSkillTimes("zhaxiang")
    end
  end,
}
local zhaxiangHit = fk.CreateTriggerSkill{
  name = "#zhaxiangHit",
  mute = true,
  frequency = Skill.Compulsory,
  events = {fk.TargetSpecified},
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and
      data.card.trueName == "slash" and data.card.color == Card.Red and
      player.phase ~= Player.NotActive and player:usedSkillTimes("zhaxiang") > 0
  end,
  on_use = function(self, event, target, player, data)
    data.disresponsive = true
  end,
}
local zhaxiang = fk.CreateTriggerSkill{
  name = "zhaxiang",
  anim_type = "drawcard",
  frequency = Skill.Compulsory,
  events = {fk.HpLost},
  on_trigger = function(self, event, target, player, data)
    for i = 1, data.num do
      self:doCost(event, target, player, data)
    end
  end,
  on_use = function(self, event, target, player, data)
    player:drawCards(3)
  end,
}
zhaxiang:addRelatedSkill(zhaxiangBuff)
zhaxiang:addRelatedSkill(zhaxiangHit)
ex__huanggai:addSkill(zhaxiang)
Fk:loadTranslationTable{
  ["ex__huanggai"] = "界黄盖",
  ["ex__kurou"] = "苦肉",
  [":ex__kurou"] = "出牌阶段限一次，你可以弃置一张牌并失去一点体力。",
  ["zhaxiang"] = "诈降",
  [":zhaxiang"] = "锁定技，每当你失去1点体力，你摸三张牌，若这是你回合内，你可以多使用一张杀且红色的杀不可闪避。",
  ["#zhaxiangHit"] = "诈降",
}

local new__zhenlie = fk.CreateTriggerSkill{
  name = "new__zhenlie",
  anim_type = "defensive",
  events = {fk.TargetConfirmed},
  can_trigger = function(self, event, target, player, data)
    if player:hasSkill(self.name) and target == player and data.from ~= player.id then
      return (data.card.type == Card.TypeTrick and data.card.sub_type ~= Card.SubtypeDelayedTrick) or data.card.trueName == "slash"
    end
  end,
  on_use = function(self, event, target, player, data)
    player.room:loseHp(player, 1, from)
    
    table.insertIfNeed(data.nullifiedTargets, player.id)

    local tar = player.room:getPlayerById(data.from)
    if tar:isAllNude() then return end
    local cid = player.room:askForCardChosen(
      player,
      tar,
      "he",
      self.name
    )

    player.room:throwCard(cid, self.name, tar, player)
  end,
}
local new__miji = fk.CreateTriggerSkill{
  name = "new__miji",
  anim_type = "drawcard",
  events = {fk.EventPhaseStart},
  can_trigger = function(self, event, target, player, data)
    return player:hasSkill(self.name) and target == player and player.phase == Player.Finish and player:isWounded()
  end,
  on_use = function(self, event, target, player, data)
    local num = player:getLostHp()

    player:drawCards(num, self.name)

    local cids = player.room:askForCard(player, 1, num, false, self.name, true)
    local cards = table.map(cids, function(p) 
      return Fk:getCardById(p)
    end)

    if #cards > 0 then
      local dummy = Fk:cloneCard'slash'
      local prompt = "#new__miji"
      local tar = player.room:askForChoosePlayers(player, table.map(player.room:getOtherPlayers(player), function(p)
        return p.id
      end), 1, 1, prompt, self.name)

      dummy:addSubcards(cards)

      player.room:obtainCard(tar[1], dummy, false, fk.ReasonGive)
    end
  end,
}
local new__wangyi = General:new(extension, "new__wangyi", "wei", 3, 3, General.Female)

new__wangyi:addSkill(new__zhenlie)
new__wangyi:addSkill(new__miji)

Fk:loadTranslationTable{
  ["new__wangyi"] = "王异",
  ["new__zhenlie"] = "贞烈",
  [":new__zhenlie"] = "当你成为其他角色使用【杀】或普通锦囊牌的目标后，你可以失去1点体力使此牌对你无效，然后你弃置其一张牌。",
  ["new__miji"] = "秘计",
  [":new__miji"] = "结束阶段，你可以摸至多X张牌（X为你已损失的体力值），然后将等量的手牌交给其他角色。",
  ["#new__miji"] = "将牌交给1名其他角色",
}

local zishu = fk.CreateTriggerSkill{
  name = "zishu",
  anim_type = "drawcard",
  frequency = Skill.Compulsory,
  events = {fk.EventPhaseStart, fk.AfterCardsMove},
  can_trigger = function(self, event, target, player, data)
    if not player:hasSkill(self.name) then return end

    if event == fk.EventPhaseStart and target.phase == Player.NotActive then
      local cards = player:getMark("#zishu-discard")

      return cards ~= 0 and cards ~= {}
    elseif event == fk.AfterCardsMove and player.phase < Player.NotActive then
      for _, d in ipairs(data) do
        return d.skillName ~= self.name and d.toArea == Player.Hand and d.to == player.id
      end
    end
  end,
  on_use = function(self, event, target, player, data)
    if event == fk.EventPhaseStart then
      local discards = player:getMark("#zishu-discard")

      for _, discid in ipairs(discards) do
        for _, card in ipairs(player.player_cards[Player.Hand]) do
          if discid == card then
            player.room:throwCard(card, self.name, player, player)
          end
        end
      end

      player.room:setPlayerMark(player, "#zishu-discard", 0)
    elseif event == fk.AfterCardsMove then
      player:drawCards(1, self.name)
    end
  end,

  refresh_events = {fk.AfterCardsMove},
  can_refresh = function(self, event, target, player, data)
    if player:hasSkill(self.name) then
      for _, d in ipairs(data) do
        return d.skillName ~= self.name and d.toArea == Player.Hand and d.to == player.id
      end
    end
  end,
  on_refresh = function(self, event, target, player, data)
    if player.phase == Player.NotActive then
      local discards = player:getMark("#zishu-discard")
      local cards = {}

      if discards == 0 then 
        discards = {}
      end

      for _, d in ipairs(data) do
        for _, info in ipairs(d.moveInfo) do
          if d.toArea == Player.Hand and d.to == player.id and info.cardId ~= nil then 
            table.insert(cards, info.cardId)
          end
        end
      end

      table.insertTable(discards, cards)
      player.room:setPlayerMark(player, "#zishu-discard", discards)
    end
  end,
}
local yingyuan = fk.CreateTriggerSkill{
  name = "yingyuan",
  anim_type = "support",
  events = {fk.CardUseFinished},
  can_trigger = function(self, event, target, player, data)
    if player:hasSkill(self.name) and target == player and player.phase == Player.Play and data.card ~= nil and player.room:getCardArea(data.card) == Card.Processing then
      local cardMark = player:getMark("#yingyuan-give")

      if cardMark == 0 then cardMark = {} end

      return not table.contains(cardMark, data.card.trueName)
    end
  end,
  on_cost = function(self, event, target, player, data)
    local prompt = "#yingyuan-give:::" .. data.card.name
    local tar = player.room:askForChoosePlayers(player, table.map(player.room:getOtherPlayers(player), function(p)
      return p.id
    end), 1, 1, prompt, self.name)

    if #tar > 0 then
      self.cost_data = tar
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local cards = data.card

    player.room:obtainCard(self.cost_data[1], cards, false, fk.ReasonGive)

    local cardMark = player:getMark("#yingyuan-give")

    if cardMark == 0 then
      cardMark = {}
    end

    table.insert(cardMark, cards.trueName)
    player.room:setPlayerMark(player, "#yingyuan-give", cardMark)
  end,

  refresh_events = {fk.EventPhaseStart},
  can_refresh = function(self, event, target, player, data)
    if player:hasSkill(self.name) and target.phase == Player.NotActive  then
      local cards = player:getMark("#yingyuan-give")

      return cards ~= 0 and cards ~= {}
    end
  end,
  on_refresh = function(self, event, target, player, data)
    player.room:setPlayerMark(player, "#yingyuan-give", 0)
  end,
}
local maliang = General:new(extension, "maliang", "shu", 3)

maliang:addSkill(zishu)
maliang:addSkill(yingyuan)

Fk:loadTranslationTable{
  ["maliang"] = "马良",
  ["zishu"] = "自书",
  [":zishu"] = "锁定技，你的回合外，你获得的牌均会在当前回合结束后置入弃牌堆；你的回合内，当你不因此技能效果获得牌时，摸一张牌。",
  ["#zishu-discard"] = "自书",
  ["yingyuan"] = "应援",
  [":yingyuan"] = "当你于回合内使用的牌置入弃牌堆后，你可以将之交给一名其他角色（相同牌名的牌每回合限一次）。",
  ["#yingyuan-give"] = "你可以选择1名其他角色，并将 %arg 交给他",
}


---@param pattern string
---@param fromPiles integer[]
---@return integer[] | nil
function getCardByPattern(room, pattern, fromPiles)
  pattern = pattern or "."
  fromPiles = room.draw_pile

  --THIS IS STUPID!
  if pattern == "damage_card" then
    pattern = "slash,duel,savage_assault,archery_attack,fire_attack,thunder"
  elseif pattern == "nondamage_card" then
    pattern = "jink,peach,dismantlement,snatch,collateral,nullification,indulgence,amazing_grace,god_salvation"..
      "crossbow,double_swords,qinggang_sword,ice_sword,axe,spear,blade,halberd,kylin_bow,eight_diagram,nioh_shield,chitu,dayuan,dilu,jueying,zixing,zhuahuangfeidian"..
      "analeptic,iron_chain,supply_shortage"..
      "guding_blade,fan,silver_lion,vine,hualiu"
  end

  local cards = {}
  for i = 1, #fromPiles, 1 do
    local card = Fk:getCardById(fromPiles[i])
    if card:matchPattern(pattern) then
      table.insertIfNeed(cards, fromPiles[i])
    end
  end
  if #cards > 0 then
    return(cards[math.random(1, #cards)])
  else
    return nil
  end
end


local guozhao = General(extension, "guozhao", "wei", 3, 3, General.Female)
local pianchong = fk.CreateTriggerSkill{
  name = "pianchong",
  anim_type = "drawcard",
  events = {fk.EventPhaseStart},
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and player.phase == Player.Draw
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local cards = {}
    table.insert(cards, getCardByPattern(room, ".|.|heart,diamond"))
    table.insert(cards, getCardByPattern(room, ".|.|spade,club"))
    if #cards > 0 then
      room:moveCards({
        ids = cards,
        to = player.id,
        toArea = Card.PlayerHand,
        moveReason = fk.ReasonPrey,
        proposer = player.id,
        skillName = self.name,
      })
    end
    local choice = room:askForChoice(player, {"red", "black"}, self.name)
    room:setPlayerMark(player, "@pianchong", choice)
    return true
  end,

  refresh_events = {fk.EventPhaseStart, fk.AfterCardsMove},
  can_refresh = function(self, event, target, player, data)
    if player:hasSkill(self.name) and not player.dead and player:getMark("@pianchong") ~= 0 then
      if event == fk.EventPhaseStart then
        return target == player and player.phase == Player.Start
      else
        local times = 0
        for _, move in ipairs(data) do
          if move.from == player.id then
            for _, info in ipairs(move.moveInfo) do
              if info.fromArea == Card.PlayerHand or info.fromArea == Card.PlayerEquip then
                local color = player:getMark("@pianchong")
                if Fk:getCardById(info.cardId):getColorString() == color then
                  times = times + 1
                end
              end
            end
          end
        end
        if times > 0 then
          player.room:setPlayerMark(player, self.name, times)
          return true
        end
      end
    end
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.EventPhaseStart then
      room:setPlayerMark(player, "@pianchong", 0)
    else
      local pattern
      local color = player:getMark("@pianchong")
      if color == "red" then
        pattern = ".|.|spade,club"
      else
        pattern = ".|.|heart,diamond"
      end
      local n = player:getMark(self.name)
      room:setPlayerMark(player, self.name, 0)
      local cards = {}
      for i = 1, n, 1 do
        table.insert(cards, getCardByPattern(room, pattern))
      end
      if #cards > 0 then
        room:moveCards({
          ids = cards,
          to = player.id,
          toArea = Card.PlayerHand,
          moveReason = fk.ReasonPrey,
          proposer = player.id,
          skillName = self.name,
        })
      end
    end
  end,
}
local zunwei = fk.CreateActiveSkill{
  name = "zunwei",
  anim_type = "drawcard",
  can_use = function(self, player)
    if player:usedSkillTimes(self.name) == 0 then
      for i = 1, 3, 1 do
        if player:getMark(self.name .. tostring(i)) == 0 then
          return true
        end
      end
    end
    return false
  end,
  card_filter = function()
    return false
  end,
  target_filter = function(self, to_select, selected)
    if #selected == 0 then
      local target = Fk:currentRoom():getPlayerById(to_select)
      local player = Fk:currentRoom():getPlayerById(Self.id)
      return (player:getMark("zunwei1") == 0 and #player.player_cards[Player.Hand] < #target.player_cards[Player.Hand]) or
       (player:getMark("zunwei2") == 0 and #player.player_cards[Player.Equip] < #target.player_cards[Player.Equip]) or
       (player:getMark("zunwei3") == 0 and player:isWounded() and player.hp < target.hp)
    end
    return false
  end,
  target_num = 1,
  card_num = 0,
  on_use = function(self, room, effect)
    local player = room:getPlayerById(effect.from)
    local target = room:getPlayerById(effect.tos[1])
    local choices = {}
    if player:getMark("zunwei1") == 0 and #player.player_cards[Player.Hand] < #target.player_cards[Player.Hand] then
      table.insert(choices, "zunwei1")
    end
    if player:getMark("zunwei2") == 0 and #player.player_cards[Player.Equip] < #target.player_cards[Player.Equip] then
      table.insert(choices, "zunwei2")
    end
    if player:getMark("zunwei3") == 0 and player:isWounded() and player.hp < target.hp then
      table.insert(choices, "zunwei3")
    end
    local choice = room:askForChoice(player, choices, self.name)
    if choice == "zunwei1" then
      player:drawCards(math.min(#target.player_cards[Player.Hand] - #player.player_cards[Player.Hand], 5))
    elseif choice == "zunwei2" then
      local n = #target.player_cards[Player.Equip] - #player.player_cards[Player.Equip]
      for i = 1, n, 1 do
        local types = {Card.SubtypeWeapon, Card.SubtypeArmor, Card.SubtypeDefensiveRide, Card.SubtypeOffensiveRide, Card.SubtypeTreasure}
        local cards = {}
        for i = 1, #room.draw_pile, 1 do
          local card = Fk:getCardById(room.draw_pile[i])
          for _, type in ipairs(types) do
            if card.sub_type == type and player:getEquipment(type) == nil then
              table.insertIfNeed(cards, room.draw_pile[i])
            end
          end
        end
        if #cards > 0 then
          local equip = cards[math.random(1, #cards)]
          room:useCard({
            from = player.id,
            tos = {{player.id}},
            card = Fk:getCardById(equip),
          })
        end
      end
    elseif choice == "zunwei3" then
      room:recover{who = player, num = math.min(player:getLostHp(), target.hp - player.hp), skillName = self.name}
    end
    room:setPlayerMark(player, choice, 1)
  end,
}
guozhao:addSkill(pianchong)
guozhao:addSkill(zunwei)
Fk:loadTranslationTable{
  ["guozhao"] = "郭照",
  ["pianchong"] = "偏宠",
  [":pianchong"] = "摸牌阶段，你可以改为从牌堆获得红牌和黑牌各一张，然后选择一项直到你的下回合开始：1.你每失去一张红色牌时摸一张黑色牌，2.你每失去一张黑色牌时摸一张红色牌。",
  ["zunwei"] = "尊位",
  [":zunwei"] = "出牌阶段限一次，你可以选择一名其他角色，并选择执行以下一项，然后移除该选项：1.将手牌数摸至与该角色相同（最多摸五张）；2.随机使用牌堆中的装备牌至与该角色相同；3.将体力回复至与该角色相同。",
  ["@pianchong"] = "偏宠",
  ["zunwei1"] = "将手牌摸至与其相同（最多摸五张）",
  ["zunwei2"] = "使用装备至与其相同",
  ["zunwei3"] = "回复体力至与其相同",
}

local caojinyu = General(extension, "caojinyu", "wei", 3, 3, General.Female)
local yuqi = fk.CreateTriggerSkill{
  name = "yuqi",
  anim_type = "masochism",
  events = {fk.Damaged},
  can_trigger = function(self, event, target, player, data)
    return player:hasSkill(self.name) and not player.dead and not target.dead and
    (target == player or player:distanceTo(target) <= player:getMark("yuqi1")) and player:getMark(self.name) < 2
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    room:addPlayerMark(player, self.name, 1)
    --local card_ids = room:getNCards(player:getMark("yuqi2"))

    --FIXME: askForCardsChosen? or yiji?
    local n1, n2 = 0, 0
    if player:getMark("yuqi2") >= player:getMark("yuqi4") then
      n2 = player:getMark("yuqi4")
      n1 = math.min(player:getMark("yuqi3"), player:getMark("yuqi2") - player:getMark("yuqi4"))
    else
      n2 = player:getMark("yuqi2")
    end
    target:drawCards(n1)
    player:drawCards(n2)
  end,

  refresh_events = {fk.DrawInitialCards, fk.EventPhaseStart},  -- FIXME: can't trigger at fk.GameStart?
  can_refresh = function(self, event, target, player, data)
    if event == fk.DrawInitialCards then
      return target == player and target:hasSkill(self.name)
    else
      return target.phase == Player.NotActive
    end
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.DrawInitialCards then
      room:setPlayerMark(player, "yuqi2", 3)
      room:setPlayerMark(player, "yuqi3", 1)
      room:setPlayerMark(player, "yuqi4", 1)
      room:setPlayerMark(player, "@" .. self.name, string.format("%d-%d-%d-%d", 0, 3, 1, 1))
    else
      room:setPlayerMark(player, self.name, 0)
    end
  end,
}
local function AddYuqi(player, skillName, num)
  local room = player.room
  local choices = {}
  for i = 1, 4, 1 do
    if player:getMark("yuqi" .. tostring(i)) < 5 then
      table.insert(choices, "yuqi" .. tostring(i))
    end
  end
  if #choices > 0 then
    local choice = room:askForChoice(player, choices, skillName)
    local x = player:getMark(choice)
    if x + num < 6 then
      x = x + num
    else
      x = 5
    end
    room:setPlayerMark(player, choice, x)
    room:setPlayerMark(player, "@yuqi", string.format("%d-%d-%d-%d",
    player:getMark("yuqi1"),
    player:getMark("yuqi2"),
    player:getMark("yuqi3"),
    player:getMark("yuqi4")))
  end
end
local shanshen = fk.CreateTriggerSkill{
  name = "shanshen",
  anim_type = "control",
  events = {fk.Death},
  can_trigger = function(self, event, target, player, data)
    return player:hasSkill(self.name) and target ~= player and not player.dead
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    AddYuqi(player, self.name, 2)
    if target:getMark(self.name) == 0 and player:isWounded() then
      room:recover{
        who = player,
        num = 1,
        skillName = self.name,
      }
    end
  end,
  refresh_events = {fk.DamageCaused},
  can_refresh = function(self, event, target, player, data)
    return target == player and target:hasSkill(self.name) and data.to:getMark(self.name) == 0
  end,
  on_refresh = function(self, event, target, player, data)
      player.room:setPlayerMark(data.to, self.name, 1)
  end,
}
local xianjing = fk.CreateTriggerSkill{
  name = "xianjing",
  anim_type = "control",
  events = {fk.EventPhaseStart},
  can_trigger = function(self, event, target, player, data)
    if target == player and player:hasSkill(self.name) and player.phase == Player.Start then
      for i = 1, 4, 1 do
        if player:getMark("yuqi" .. tostring(i)) < 5 then
          return true
        end
      end
    end
    return false
  end,
  on_use = function(self, event, target, player, data)
    AddYuqi(player, self.name, 1)
    if not player:isWounded() then
      AddYuqi(player, self.name, 1)
    end
  end,
}
caojinyu:addSkill(yuqi)
caojinyu:addSkill(shanshen)
caojinyu:addSkill(xianjing)
Fk:loadTranslationTable{
  ["caojinyu"] = "曹金玉",
  ["yuqi"] = "隅泣",
  [":yuqi"] = "当有角色受到伤害后，若你与其距离0或者更少，你可以观看牌堆顶的三张牌，将其中至多一张交给受伤角色，至多一张自己获得，剩余的牌放回牌堆顶。（每回合限触发2次）",
  ["shanshen"] = "善身",
  [":shanshen"] = "当有角色死亡时，你可令“隅泣”中的一个数字+2（单项不能超过5）。然后若你没有对死亡角色造成过伤害，你回复1点体力。",
  ["xianjing"] = "娴静",
  [":xianjing"] = "准备阶段，你可令“隅泣”中的一个数字+1（单项不能超过5）。若你满体力值，则再令“隅泣”中的一个数字+1。",
  ["@yuqi"] = "隅泣",
  ["yuqi1"] = "距离",
  ["yuqi2"] = "观看牌数",
  ["yuqi3"] = "交给受伤角色牌数",
  ["yuqi4"] = "自己获得牌数",
}

local zhujianping = General(extension, "zhujianping", "qun", 3)
local xiangmian = fk.CreateActiveSkill{
  name = "xiangmian",
  anim_type = "offensive",
  can_use = function(self, player)
    return player:usedSkillTimes(self.name) < 1
  end,
  card_filter = function()
    return false
  end,
  target_filter = function(self, to_select, selected)
    return #selected == 0 and to_select ~= Self.id and Fk:currentRoom():getPlayerById(to_select):getMark("xiangmian_suit") == 0
  end,
  target_num = 1,
  on_use = function(self, room, effect)
    local target = room:getPlayerById(effect.tos[1])
    local judge = {
      who = target,
      reason = self.name,
      pattern = ".",
    }
    room:judge(judge)
    room:setPlayerMark(target, "@xiangmian", string.format("%s-%d",
    Fk:translate(judge.card:getSuitString()),
    judge.card.number))
    room:setPlayerMark(target, "xiangmian_suit", judge.card:getSuitString())
    room:setPlayerMark(target, "xiangmian_num", judge.card.number)
  end,
}
local xiangmian_kill = fk.CreateTriggerSkill{
  name = "#xiangmian_kill",
  refresh_events = {fk.CardUseFinished},
  can_refresh = function(self, event, target, player, data)
    return target == player and target:getMark("xiangmian_num") > 0
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    room:addPlayerMark(target, self.name, 1)
    if data.card:getSuitString() == target:getMark("xiangmian_suit") or target:getMark(self.name) == target:getMark("xiangmian_num") then
      room:setPlayerMark(target, "xiangmian_num", 0)
      room:setPlayerMark(target, "@xiangmian", 0)
      room:loseHp(target, target.hp, "xiangmian")
    end
  end,
}
local tianji = fk.CreateTriggerSkill{
  name = "tianji",
  events = {fk.FinishJudge},
  frequency = Skill.Compulsory,
  can_trigger = function(self, event, target, player, data)
    return player:hasSkill(self.name)
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local card = data.card
    local cards = {}
    table.insert(cards, getCardByPattern(room, ".|.|.|.|.|"..card:getTypeString()))
    table.insert(cards, getCardByPattern(room, ".|.|"..card:getSuitString()))
    table.insert(cards, getCardByPattern(room, ".|"..card.number))
    if #cards > 0 then
      room:moveCards({
        ids = cards,
        to = player.id,
        toArea = Card.PlayerHand,
        moveReason = fk.ReasonPrey,
        proposer = player.id,
        skillName = self.name,
      })
    end
  end,
}
xiangmian:addRelatedSkill(xiangmian_kill)
zhujianping:addSkill(xiangmian)
zhujianping:addSkill(tianji)
Fk:loadTranslationTable{
  ["zhujianping"] = "朱建平",
  ["xiangmian"] = "相面",
  [":xiangmian"] = "出牌阶段限一次，你可以令一名其他角色进行一次判定，当该角色使用判定花色的牌或使用第X张牌后（X为判定点数），其失去所有体力。每名其他角色限一次。",
  ["tianji"] = "天机",
  [":tianji"] = "锁定技，生效后的判定牌进入弃牌堆后，你从牌堆随机获得与该牌类型、花色和点数相同的牌各一张。",
  ["@xiangmian"] = "相面",
}

local zhouxuan = General(extension, "zhouxuan", "wei", 3)
local wumei = fk.CreateTriggerSkill{
  name = "wumei",
  anim_type = "control",
  events = {fk.EventPhaseStart},
  can_trigger = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and player.phase == Player.RoundStart and player:getMark("wumei") == 0
  end,
  on_cost = function(self, event, target, player, data)
    local p = player.room:askForChoosePlayers(player, table.map(player.room:getAlivePlayers(), function(p) return p.id end), 1, 1, "#wumei-choose", self.name)
    if #p > 0 then
      self.cost_data = p[1]
      return true
    end
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    room:addPlayerMark(player, "wumei", 1)
    for _, p in ipairs(room:getAlivePlayers()) do
      room:setPlayerMark(p, "wumei_hp", p.hp)
    end
    local to = room:getPlayerById(self.cost_data)
    room:addPlayerMark(to, "wumei_extra", 1)
    to:gainAnExtraTurn()
  end,

  refresh_events = {fk.EventPhaseStart, fk.TurnStart},
  can_refresh = function(self, event, target, player, data)
    if event == fk.EventPhaseStart then
      return player.phase == Player.NotActive and player:getMark("wumei_extra") > 0
    else
      return target.seat == 1
    end
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.EventPhaseStart then
      room:setPlayerMark(player, "wumei_extra", 0)
      for _, p in ipairs(room:getAlivePlayers()) do
        p.hp = p:getMark("wumei_hp")
        room:broadcastProperty(p, "hp")
        room:setPlayerMark(p, "wumei_hp", 0)
      end
    else
      for _, p in ipairs(room:getAlivePlayers()) do
        if p:getMark("wumei") > 0 then
          room:setPlayerMark(p, "wumei", 0)
        end
      end
    end
  end,
}
local zhanmeng = fk.CreateTriggerSkill{
  name = "zhanmeng",
  events = {fk.CardUsing},
  can_trigger = function(self, event, target, player, data)
    if target == player and player:hasSkill(self.name) then
      for i = 1, 3, 1 do
        if player:getMark(self.name .. tostring(i)) == 0 then
          return true
        end
      end
    end
  end,
  on_cost = function(self, event, target, player, data)
    local room = player.room
    local choices = {"Cancel"}
    self.cost_data = {}
    if player:getMark("zhanmeng1") == 0 and table.contains(room:getTag("zhanmeng1"), data.card.trueName) then
      table.insert(choices, "zhanmeng1")
    end
    if player:getMark("zhanmeng2") == 0 then
      table.insert(choices, "zhanmeng2")
    end
    local tos = {}
    if player:getMark("zhanmeng3") == 0 then
      for _, p in ipairs(room:getOtherPlayers(player)) do
        if #p.player_cards[Player.Hand] + #p.player_cards[Player.Equip] > 1 then
          table.insertIfNeed(choices, "zhanmeng3")
          table.insert(tos, p)
        end
      end
    end
    local choice = room:askForChoice(player, choices, self.name)
    if choice == "Cancel" then return end
    self.cost_data[1] = choice
    if choice == "zhanmeng3" then
      local p = room:askForChoosePlayers(player, table.map(tos, function(p) return p.id end), 1, 1, "#zhanmeng-choose", self.name)
      if #p > 0 then
        self.cost_data[2] = p[1]
      end
    end
    return #self.cost_data > 0
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local choice = self.cost_data[1]
    room:setPlayerMark(player, choice, 1)
    if choice == "zhanmeng1" then
      local card = {getCardByPattern(room, "nondamage_card")}
      if #card > 0 then
        room:moveCards({
          ids = card,
          to = player.id,
          toArea = Card.PlayerHand,
          moveReason = fk.ReasonPrey,
          proposer = player.id,
          skillName = self.name,
        })
      end
    elseif choice == "zhanmeng2" then
      room:setPlayerMark(player, "zhanmeng2_invoke", data.card.trueName)
    elseif choice == "zhanmeng3" then
      local p = room:getPlayerById(self.cost_data[2])
      --ATTENTION: this skill may discard cards after target filted, so cards like dismantlement,snatch,collateral,fire_attack should check again before effect!
      local discards = room:askForDiscard(p, 2, 2, true, self.name, false)
      if Fk:getCardById(discards[1]).number + Fk:getCardById(discards[2]).number > 10 then
        room:damage{
          from = player,
          to = p,
          damage = 1,
          damageType = fk.FireDamage,
          skillName = self.name,
        }
      end
    end
  end,

  refresh_events = {fk.EventPhaseStart},
  can_refresh = function(self, event, target, player, data)
    return target == player and player:hasSkill(self.name) and player.phase == Player.NotActive
  end,
  on_refresh = function(self, event, target, player, data)
    for i = 1, 3, 1 do
      player.room:setPlayerMark(player, self.name .. tostring(i), 0)
    end
  end,
}
local zhanmeng_record = fk.CreateTriggerSkill{
  name = "#zhanmeng_record",

  refresh_events = {fk.CardUsing, fk.EventPhaseStart},
  can_refresh = function(self, event, target, player, data)
    if target == player then
      if event == fk.CardUsing then
        return true
      else
        return player.phase == Player.Start or player.phase == Player.NotActive
      end
    end
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.CardUsing then
      local zhanmeng2 = room:getTag("zhanmeng2")
      if type(zhanmeng2) ~= "table" then
        zhanmeng2 = {}
      end
      if not table.contains(zhanmeng2, data.card.trueName) then
        table.insert(zhanmeng2, data.card.trueName)
        room:setTag("zhanmeng2", zhanmeng2)
      end
      for _, p in ipairs(room:getAlivePlayers()) do
        if p:getMark("zhanmeng2_get") == data.card.trueName then
          room:setPlayerMark(p, "zhanmeng2_get", 0)
          local card = {getCardByPattern(room, "damage_card")}
          if #card > 0 then
            room:moveCards({
              ids = card,
              to = p.id,
              toArea = Card.PlayerHand,
              moveReason = fk.ReasonPrey,
              proposer = p.id,
              skillName = "zhanmeng",
            })
          end
        end
      end
    else
      if player.phase == Player.Start then
        local zhanmeng2 = room:getTag("zhanmeng2")
        if type(zhanmeng2) ~= "table" then
          zhanmeng2 = {}
        end
        room:setTag("zhanmeng1", zhanmeng2)  --cards used in last turn
        zhanmeng2 = {}
        room:setTag("zhanmeng2", zhanmeng2)  --cards used in current turn
        for _, p in ipairs(room:getAlivePlayers()) do
          if type(p:getMark("zhanmeng2_invoke")) == "string" then
            room:setPlayerMark(p, "zhanmeng2_get", p:getMark("zhanmeng2_invoke"))
            room:setPlayerMark(p, "zhanmeng2_invoke", 0)
          end
        end
      elseif player.phase == Player.NotActive then
        for _, p in ipairs(room:getAlivePlayers()) do
          room:setPlayerMark(p, "zhanmeng2_get", 0)
        end
      end
    end
  end,
}
zhanmeng:addRelatedSkill(zhanmeng_record)
zhouxuan:addSkill(wumei)
zhouxuan:addSkill(zhanmeng)
Fk:loadTranslationTable{
  ["zhouxuan"] = "周宣",
  ["wumei"] = "寤寐",
  [":wumei"] = "每轮限一次，回合开始前，你可以令一名角色执行一个额外的回合：该回合结束时，将所有存活角色的体力值调整为此额外回合开始时的数值。",
  ["zhanmeng"] = "占梦",
  [":zhanmeng"] = "你使用牌时，可以执行以下一项（每回合每项各限一次）：1.上一回合内，若没有同名牌被使用，你获得一张非伤害牌。2.下一回合内，当同名牌首次被使用后，你获得一张伤害牌。3.令一名其他角色弃置两张牌，若点数之和大于10，对其造成1点火焰伤害。",
  ["#wumei-choose"] = "占梦: 你可以令一名角色执行一个额外的回合",
  ["zhanmeng1"] = "你获得一张非伤害牌",
  ["zhanmeng2"] = "下一回合内，当同名牌首次被使用后，你获得一张伤害牌",
  ["zhanmeng3"] = "令一名其他角色弃置两张牌，若点数之和大于10，对其造成1点火焰伤害",
  ["#zhanmeng-choose"] = "占梦: 令一名其他角色弃置两张牌，若点数之和大于10，对其造成1点火焰伤害",
}

return {extension}
